在 Day 04 中我們建立了密碼學的核心觀念: 「演算法是公開的,安全性的關鍵全在於金鑰」 (Kerckhoffs's principle)。既然整套系統的防禦重任都落在金鑰身上,那麼這把關鍵的金鑰究竟該如何產生?
要讓攻擊者無法破解,金鑰就必須做到「完全無法被預測」,這時我們就必須仰賴 亂數產生器(Random Number Generator, RNG) 來達到。
在電腦科學與密碼學中,亂數產生器主要分為以下三種層次:
0 或 1 的機率無法顯著高於 $50%$(與猜硬幣無異)。作為 Java 開發者,在程式碼中使用亂數時必須特別注意類別的選擇,選錯類別會直接導致系統產生嚴重的安全漏洞。
java.util.Random 與 ThreadLocalRandomjava.util.Random 底層採用 線性同餘法 (Linear Congruential Generator, LCG):
Random unsafeRandom = new Random();
int sessionToken = unsafeRandom.nextInt(); // 可被逆向推算!
java.security.SecureRandomSecureRandom 是 Java JCA 架構中的 Engine Class,底層會向作業系統索取熵源(如 Linux 的 /dev/urandom 或 Windows 的 CryptoAPI),並結合 SHA1PRNG、HMAC-DRBG 或 AES-DRBG 等演算法產生 CSPRNG 強度的亂數。
import java.security.SecureRandom;
import java.util.Base64;
public class SecureRandomDemo {
public static void main(String[] args) {
// 1. 建立 CSPRNG 強度的 SecureRandom 實體
SecureRandom secureRandom = new SecureRandom();
// 2. 生成 128-bit (16 bytes) 的隨機 AES 金鑰或 IV
byte[] keyBytes = new byte[16];
secureRandom.nextBytes(keyBytes); // 安全填充隨機位元
// 3. 生成安全 Session Token (Base64 編碼)
String safeToken = Base64.getUrlEncoder().withoutPadding().encodeToString(keyBytes);
System.out.println("安全生成的 Token: " + safeToken);
}
}